package com.ladlee.parking.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ladlee.parking.constant.CommonConstants;
import com.ladlee.parking.entity.SecurityUser;
import com.ladlee.parking.entity.SysRole;
import com.ladlee.parking.entity.SysUser;
import com.ladlee.parking.entity.vo.MenuVO;
import com.ladlee.parking.service.SysMenuService;
import com.ladlee.parking.service.SysRoleService;
import com.ladlee.parking.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service("sysUserDetailsService")
public class SysUserDetailsService implements UserDetailsService {

    @Autowired
    SysUserService sysUserService;
    @Autowired
    SysRoleService sysRoleService;
    @Autowired
    SysMenuService sysMenuService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysUser sysUser = sysUserService.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));
        if (sysUser == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        // 设置角色列表 （ID）
        List<Integer> roleIds = sysRoleService.findRolesByUserId(sysUser.getUserId())
                .stream()
                .map(SysRole::getRoleId)
                .collect(Collectors.toList());
        //设置权限列表（menu.permission）
        List<MenuVO> menus = new ArrayList<>();
        Set<String> permissions = new HashSet<>();
        roleIds.forEach(roleId -> {
            List<MenuVO> menuVOS = sysMenuService.findMenuByRoleId(roleId);
            if (CollUtil.isNotEmpty(menuVOS)) {
                menus.addAll(menuVOS);
            }
            List<String> permissionList = menuVOS.stream()
                    .filter(menuVo -> StrUtil.isNotBlank(menuVo.getPermission()))
                    .map(MenuVO::getPermission)
                    .collect(Collectors.toList());
            permissions.addAll(permissionList);
        });
        Set<String> dbAuthsSet = new HashSet<>();
        List<MenuVO> menuTree = Collections.emptyList();
        if (CollUtil.isNotEmpty(roleIds)) {
            // 获取角色
            roleIds.forEach(roleId -> dbAuthsSet.add(CommonConstants.ROLE + roleId));
            // 获取资源
            dbAuthsSet.addAll(permissions);
            // 菜单列表
            if (CollUtil.isNotEmpty(menus)) {
                menuTree = getTree(menus, -1);
            }
        }
        Collection<? extends GrantedAuthority> authorities
                = AuthorityUtils.createAuthorityList(dbAuthsSet.toArray(new String[0]));
        boolean enabled = StrUtil.equals(sysUser.getLockFlag(), CommonConstants.STATUS_NORMAL);

        return new SecurityUser(sysUser.getUserId(), sysUser.getDeptId(), sysUser.getTenantId(), sysUser.getUsername(), CommonConstants.BCRYPT + sysUser.getPassword(), enabled,
                true, true, !CommonConstants.STATUS_LOCK.equals(sysUser.getLockFlag()), authorities, menuTree);
    }


    private List<MenuVO> getTree(List<MenuVO> roots, Integer parentId) {
        // 获取所有的父级节点
        List<MenuVO> treeRoot = roots.stream().filter(node -> ObjectUtil.equal(node.getParentId(), parentId)).collect(Collectors.toList());
        roots.removeAll(treeRoot);
        List<MenuVO> result = new ArrayList<>();
        for (MenuVO root : treeRoot) {
            result.add(getChild(roots, root));
        }
        return result;
    }

    /**
     * 递归过获取无限级子节点
     *
     * @return
     */
    private MenuVO getChild(List<MenuVO> nodeList, MenuVO node) {
        List<MenuVO> childList = getChildList(nodeList, node);
        if (CollUtil.isNotEmpty(childList)) {
            // 移除已经遍历过的节点
            nodeList.removeAll(childList);
            for (MenuVO child : childList) {
                node.getChildes().add(getChild(nodeList, child));
            }
        }
        return node;
    }

    /**
     * 得到子节点列表
     *
     * @return
     */
    private List<MenuVO> getChildList(List<MenuVO> nodeList, MenuVO node) {
        List<MenuVO> dataList = new ArrayList<>();
        for (MenuVO dto : nodeList) {
            if (ObjectUtil.isEmpty(dto.getParentId())) {
                continue;
            }
            if (ObjectUtil.equal(dto.getParentId(), node.getMenuId())) {
                dataList.add(dto);
            }
        }
        return dataList;
    }
}
